<?php
/* SVN FILE: $Id: marketRegistry.php 248 2009-11-12 16:29:29Z supersmashbrothers $ */
/**
* ibMarket 2
* IP.Board 3.0
* ibMarket Registry
* ibMarket common functions
*
* @author $Author: supersmashbrothers $
* @copyright $Copyright$
* @version $Revision: 248 $
* @lastrevision $Date: 2009-11-12 16:29:29 +0000 (Thu, 12 Nov 2009) $
* @modifiedby $LastChangedBy: supersmashbrothers $
* @lastmodified $LastChangedDate: 2009-11-12 16:29:29 +0000 (Thu, 12 Nov 2009) $
* @filesource $URL: http://ipb-ibmarket.googlecode.com/svn/ibmarket2/trunk/admin/applications_addon/other/ibmarket/sources/marketRegistry.php $
*/

if(!class_exists('ipsRegistry'))
{
	throw new Exception("ipsRegistry should be loaded");
}

define("_MARKET_LIMIT_UPDATE", IN_DEV ? 0 : 1);

final class marketRegistry
{
	/**
	 * The location of the latest versions of ibMarket
	 *
	 * @access	public
	 * @var		string
	 */
	const versionXML		= "http://ipb-ibmarket.googlecode.com/svn/ibmarket2/versions.xml";
	
	/**
	 * The location of the support topic for ibMarket
	 *
	 * @access	public
	 * @var		string
	 */
	const supportTopic		= "http://forums.invisionize.com/index.php?showtopic=125348";
	
	/**
	 * The location of to the bug reports of ibMarket
	 *
	 * @access	public
	 * @var		string
	 */
	const reportBugs		= "http://code.google.com/p/ipb-ibmarket/issues/list";
	
	/**
	 * The location of where to downlaoad ibMarket
	 *
	 * @access	public
	 * @var		string
	 */
	const download_ibMarket	= "http://code.google.com/p/ipb-ibmarket/downloads/list";
	
	/**
	 * The location of the wiki to ibMarket
	 *
	 * @access	public
	 * @var		string
	 */
	const wiki				= "http://code.google.com/p/ipb-ibmarket/w/list";
	
	/**
	 * ibMarket is in development or not
	 *
	 * @access	public
	 * @var		string
	 */
	const unstable			= true;
	
	/**
	 * The location of the ibMarket website
	 *
	 * @access	public
	 * @var		string
	 */
	const website			= "http://ipb-ibmarket.googlecode.com/";
	
	/**
	 * The location of the ibMarket update feeds
	 *
	 * @access	public
	 * @var		string
	 */
	const updates			= "http://code.google.com/feeds/p/ipb-ibmarket/updates/basic";
	
	/**
	 * Limits the updates on restocking
	 * 0 for unlimited restocking updates
	 *
	 * @access	public
	 * @var		string
	 */
	const limitUpdate = _MARKET_LIMIT_UPDATE;
	
	/**
	 * Counts the number of updates, should be used with items and plugins
	 *
	 * @access	public
	 * @var		int
	 */
	public static $UPDATE = 0;
	
	/**
	 * Sets when the class is initiated
	 *
	 * @access	private
	 * @var		int
	 */
	private static $_is_init = 0;
	
	/**
	 * The location of the ibMarket images on the server
	 *
	 * @access	private
	 * @var		string
	 */
	private static $image_server_path;
	
	/**
	 * The url to the ibMarket images on the server
	 *
	 * @access	private
	 * @var		string
	 */
	private static $image_url_path;
	
	/**
	 * The tree of all the ibMarket categories
	 *
	 * @access	private
	 * @var		array
	 */
	private static $categoryTree = array();
	
	/**
	 * Makes a list of the order of categories
	 *
	 * @access	private
	 * @var		array
	 */
	private static $categoryOrder = array();
	
	/**
	 * Makes a list of the order of categories
	 *
	 * @access	private
	 * @var		array
	 */
	private static $categoryDepth = array();
	
	/**
	 * All the ibMarket items listed by Categories
	 *
	 * @access	private
	 * @var		array
	 */
	private static $itemByCategories = array();
	
	/**
	 * All the ibMarket items listed by their files
	 *
	 * @access	private
	 * @var		array
	 */
	private static $itemByFiles = array();
	
	/**
	 * All the item objects instantiated
	 *
	 * @access	private
	 * @var		string
	 */
	private static $itemsLoaded = array();
	
	/**
	 * All the plugins objects instantiated
	 *
	 * @access	private
	 * @var		array
	 */
	private static $pluginLoaded = array();
	
	/**
	 * All the icons cached into the array
	 *
	 * @access	private
	 * @var		array
	 */
	private static $iconsList = array();
	
	/**
	 * All the inventory from the database
	 *
	 * @access	private
	 * @var		array
	 */
	private static $inventoryItem = array(0=>array());
	
	/**
	 * The ReflectionClass of item template
	 *
	 * @access	private
	 * @var		ReflectionClass
	 */
	private static $itemTemplate;
	
	/**
	 * The ReflectionClass of plugin template
	 *
	 * @access	private
	 * @var		string
	 */
	private static $pluginTemplate;
	
	/**
	 * Turn off constructor
	 *
	 * @access	private
	 * @return	void
	 */
	private function __construct() {}
	
	/**
	 * Sets up this class. To be called first and only once.
	 *
	 * @access	private
	 * @return	void
	 */
	public static function __init()
	{
		if(self::$_is_init != 0)
		{
			return;
		}
		$_pre_load = IPSDebug::getMemoryDebugFlag();
		
		self::$_is_init = 1;
		
		$settings =& ipsRegistry::fetchSettings();
		
		$settings['market_images_path']	= self::$image_server_path	= DOC_IPS_ROOT_PATH."/images/market";
		$settings['market_images_url']	= self::$image_url_path		= $settings['board_url']."/images/market";
		
		require_once( IPSLib::getAppDir('ibmarket')."/sources/marketFormatter.php");
		require_once( IPSLib::getAppDir('ibmarket')."/sources/numbers.php");
		require_once( IPSLib::getAppDir('ibmarket')."/sources/sortArrays.php");
		require_once( IPSLib::getAppDir('ibmarket')."/sources/templateItem.php");
		require_once( IPSLib::getAppDir('ibmarket')."/sources/templatePlugin.php");
		
		self::$itemTemplate		= new ReflectionClass('templateItem');
		self::$pluginTemplate	= new ReflectionClass('templatePlugin');
		
		IPSDebug::setMemoryDebugFlag( "ibMarket: ibMarket Class initialized", $_pre_load );
	}
	
	/**
	 * Sets up this class. To be called first and only once.
	 *
	 * @access	private
	 * @return	void
	 */
	public static function __setup()
	{
		if(self::$_is_init != 1)
		{
			return;
		}
		$_pre_load = IPSDebug::getMemoryDebugFlag();
		
		self::$_is_init = 2;
		
		IPSText::getTextClass('bbcode')->allow_update_caches	= false;
		IPSText::getTextClass('bbcode')->parse_smilies			= 1;
		IPSText::getTextClass('bbcode')->parse_html				= 0;
		IPSText::getTextClass('bbcode')->parse_nl2br			= 1;
		IPSText::getTextClass('bbcode')->parse_bbcode			= 1;
		IPSText::getTextClass('bbcode')->parsing_section		= 'ibmarket';
		IPSText::getTextClass('bbcode')->parsing_mgroup			= ipsRegistry::member()->getProperty('member_group_id');
		IPSText::getTextClass('bbcode')->parsing_mgroup_others	= ipsRegistry::member()->getProperty('mgroup_others');	
		
		IPSText::getTextClass('editor')->from_acp				= IN_ACP;
		
		self::processCache();
		
		// For skin templates
		ipsRegistry::setClass('marketRegistry', new self());
		
		IPSDebug::setMemoryDebugFlag( "ibMarket: ibMarket Class setup", $_pre_load );
	}
	
	/**
	 * Sets up this class. To be called first and only once.
	 *
	 * @todo Update to make it fully working and take out code comments
	 * @access	private
	 * @return	void
	 */
	private static function processCache()
	{
		$_pre_load = IPSDebug::getMemoryDebugFlag();
		
		$input =& ipsRegistry::fetchRequest();
		$caches =& ipsRegistry::cache()->fetchCaches();
		$settings =& ipsRegistry::fetchSettings();
		
		if(!is_array($caches['market_category']))
		{
			$caches['market_category'] = array();
		}
		foreach($caches['market_category'] as $cat_id => $category)
		{
			$caches['market_category'][$cat_id]['cat_description'] = IPSText::getTextClass('bbcode')->preDisplayParse(IPSText::getTextClass('bbcode')->preDbParse($category['cat_description']));
			self::$categoryTree[$category['cat_parent_id']][$cat_id] = &$caches['market_category'][$cat_id];
		}
		foreach(array_keys(self::$categoryTree) as $id)
		{
			uasort(self::$categoryTree[$id],array('sortArrays','orderCategory'));
		}
		
		self::buildCategoryOrder(self::$categoryOrder);
		
		if(!is_array($caches['market_items']))
		{
			$caches['market_items'] = array();
		}
		// Do the restock
		// But not on post requests
		if($input['request_method'] == 'get' && IN_ACP == 0 && $input['module'] != 'ajax')
		{
			foreach($caches['market_items'] as $item_id => $item)
			{
				if( (!self::limitUpdate || self::$UPDATE < self::limitUpdate) &&
					numbers::compare($caches['market_items'][$item_id]['stock']) >= 0 && 
					$caches['market_items'][$item_id]['restock'] && 
					$caches['market_items'][$item_id]['restock_time'] && 
					$caches['market_items'][$item_id]['restock_time'] <= IPS_UNIX_TIME_NOW
				   )
				{
					$caches['market_items'][$item_id]['stock'] = numbers::add($caches['market_items'][$item_id]['stock'],$caches['market_items'][$item_id]['restock_howmuch']);
					if($caches['market_items'][$item_id]['restock'] == 3)
					{
						$caches['market_items'][$item_id]['restock_when'] = $caches['market_items'][$item_id]['restock_time'];
					}
					$caches['market_items'][$item_id]['restock_time'] = self::nextRestockTime($caches['market_items'][$item_id],$caches['market_items'][$item_id]['restock_time']);
					
					$update_item = array(
											'stock' => $caches['market_items'][$item_id]['stock'],
											'restock_time' => $caches['market_items'][$item_id]['restock_time'],
											'restock_when' => $caches['market_items'][$item_id]['restock_when'],
										);
					
					self::getItem($caches['market_items'][$item_id], false)->onItemRestock($update_item);
					
					ipsRegistry::DB()->update('market_items',$update_item,"item_id=".$item_id);
					self::$UPDATE++;
				}
			}
		}
		if(self::$UPDATE > 0)
		{
			ipsRegistry::cache()->rebuildCache('market_items','ibmarket');
		}
		foreach($caches['market_items'] as $item_id => $item)
		{
			$caches['market_items'][$item_id]['price'] = numbers::multiply($caches['market_category'][$item['category']]['price_multiplier'],$item['base_price'],ipsRegistry::member()->getProperty('market_deduct'));
			$caches['market_items'][$item_id]['resell'] = numbers::multiply($caches['market_category'][$item['category']]['price_multiplier'],$item['base_resell'],ipsRegistry::member()->getProperty('market_deduct'));
			
			if($caches['market_items'][$item_id]['price'])
			{
				$caches['market_items'][$item_id]['total_tax'] = numbers::add(numbers::parseFloat($settings['market_global_tax']),$caches['market_category'][$item['category']]['cat_tax'],ipsRegistry::member()->getProperty('g_market_tax'),ipsRegistry::member()->getProperty('market_tax'),$item['tax']);
			}
			else
			{
				$caches['market_items'][$item_id]['total_tax'] = 0;
			}
			
			$caches['market_items'][$item_id]['tax_amount'] = numbers::round(numbers::divide(numbers::multiply($caches['market_items'][$item_id]['price'],$caches['market_items'][$item_id]['total_tax']),100));
			
			if($settings['market_resell_tax'])
			{
				$caches['market_items'][$item_id]['resell'] = numbers::add($caches['market_items'][$item_id]['resell'],$caches['market_items'][$item_id]['tax_amount']);
			}
			
			self::getItem($caches['market_items'][$item_id]);
			
			$null = array();
			$caches['market_items'][$item_id]['can_resell'] = $caches['market_items'][$item_id]['allow_resell'] && self::$itemsLoaded[$item_id]->publicOnResoldItem($null);
			$null = array();
			$caches['market_items'][$item_id]['hide_item'] = $caches['market_items'][$item_id]['hide_item'] || !self::$itemsLoaded[$item_id]->publicOnCreateItem($null);
			
			$caches['market_items'][$item_id]['item_description'] = IPSText::getTextClass('bbcode')->preDisplayParse(IPSText::getTextClass('bbcode')->preDbParse($item['item_description']));
			
			$caches['market_items'][$item_id]['expire'] = $item['expire_time'] * $item['expire_unit'];
			
			self::$itemByCategories[$item['category']][$item_id] = &$caches['market_items'][$item_id];
			self::$itemByFiles[$item['filename']][$item_id] = &$caches['market_items'][$item_id];
		}
		
		$all_groups = array_merge(array(-1),array_keys($caches['group_cache']));
		if(!is_array($caches['market_plugin']))
		{
			$caches['market_plugin'] = array();
		}
		foreach($caches['market_plugin'] as $directory => $plugin)
		{
			if($caches['market_plugin'][$directory]['view_permission'] == -1)
			{
				$caches['market_plugin'][$directory]['view_permission'] = $all_groups;
			}
			else
			{
				$caches['market_plugin'][$directory]['view_permission'] = explode(",",$plugin['view_permission']);
			}
			if($caches['market_plugin'][$directory]['use_permission'] == -1)
			{
				$caches['market_plugin'][$directory]['use_permission'] = $all_groups;
			}
			else
			{
				$caches['market_plugin'][$directory]['use_permission'] = explode(",",$plugin['use_permission']);
			}
			
			if(file_exists(IPSLib::getAppDir('ibmarket')."/plugins/".$directory."/globalLoader.php"))
			{
				require_once(IPSLib::getAppDir('ibmarket')."/plugins/".$directory."/globalLoader.php");
			}
			
			if(ipsRegistry::$request['plugin'] == $directory)
			{
				if(file_exists(IPSLib::getAppDir('ibmarket')."/plugins/".$directory."/loader.php"))
				{
					require_once(IPSLib::getAppDir('ibmarket')."/plugins/".$directory."/loader.php");
				}
			}
		}
		
		$update = self::$UPDATE;
		$translate = array('m'=>'member','g'=>'group');
		if(!is_array($caches['market_wages']))
		{
			$caches['market_wages']['id'] = array();
		}
		if($input['request_method'] == 'get' && IN_ACP == 0 && $input['module'] != 'ajax')
		{
			foreach($caches['market_wages']['id'] as $wage)
			{
				if( (!self::limitUpdate || self::$UPDATE < self::limitUpdate) && $wage['next_payment'] <= IPS_UNIX_TIME_NOW )
				{
					$me = false;
					$where = "";
					if($wage['to_who'] == 'm')
					{
						$where = "member_id = ".$wage['id_who'];
						$me = ipsRegistry::member()->getProperty('member_id') == $wage['id_who'];
					}
					elseif($wage['to_who'] == 'g')
					{
						$where = "member_group_id = ".$wage['id_who'];
						$me = ipsRegistry::member()->getProperty('member_group_id') == $wage['id_who'];
					}
					else
					{
						$where = "member_id < 0";
					}
					self::$UPDATE++;
					ipsRegistry::DB()->update('members',$settings['market_members_field']."=".$settings['market_members_field']."+".$wage['how_much'],$where,false,true);
					
					if($wage['w_how'] == 1)
					{
						$caches['market_wages']['id'][$wage['w_id']]['w_when'] = $wage['next_payment'];
					}
					ipsRegistry::DB()->update('market_wages',array(
																		'w_when' => $caches['market_wages']['id'][$wage['w_id']]['w_when'],
																		'next_payment' => self::nextWageTime($wage,$wage['next_payment']),
												),"w_id=".$wage['w_id']);
					ipsRegistry::DB()->insert('market_wages_collected',array(
																					'time_collected' => $wage['next_payment'],
																					'to_who' => $wage['to_who'],
																					'id_who' => $wage['id_who'],
																					'how_much' => $wage['how_much'],
													)							);
					
					// Update member points
					if($me)
					{
						ipsRegistry::member()->setProperty($settings['market_members_field'],numbers::add(ipsRegistry::member()->getProperty($settings['market_members_field']),$wage['how_much']));
					}
				}
			}
		}
		if(self::$UPDATE > $update)
		{
			ipsRegistry::cache()->rebuildCache('market_wages','ibmarket');
		}
		$caches['market_wages']['member'] = array();
		$caches['market_wages']['group'] = array();
		foreach($caches['market_wages']['id'] as $wage)
		{
			$caches['market_wages'][$translate[$wage['to_who']]][$wage['w_id']] = &$caches['market_wages']['id'][$wage['w_id']];
		}
		
		if(!is_array($caches['market_taxes']))
		{
			$caches['market_taxes']['id'] = array();
		}
		$caches['market_taxes']['hand'] = array();
		$caches['market_taxes']['post'] = array();
		if(count($caches['market_taxes']['id']) && $input['request_method'] == 'get' && IN_ACP == 0 && $input['module'] != 'ajax' && ipsRegistry::member()->getProperty('g_market_use') && ipsRegistry::member()->getProperty('member_id') && (!self::limitUpdate || self::$UPDATE < self::limitUpdate))
		{
			$taxed = 0;
			$earliest = IPS_UNIX_TIME_NOW;
			$last_collected = array();
			$cached_posts = array();
			ipsRegistry::DB()->build(array('select'=>'MAX(l_time) as last_time, tax_id','from'=>'market_tax_logs','where'=>"member_id=".ipsRegistry::member()->getProperty('member_id'),'group'=>'tax_id'));
			$q = ipsRegistry::DB()->execute();
			while($log = ipsRegistry::DB()->fetch($q))
			{
				if(is_array($caches['market_taxes']['id'][$log['tax_id']]))
				{
					$last_collected[$log['tax_id']] = $log['last_time'];
					if($caches['market_taxes']['id'][$log['tax_id']]['applying'] == 'post' && $log['last_time'] < $earliest)
					{
						$earliest = $log['last_time'];
					}
				}
			}
			if($earliest != $time)
			{
				ipsRegistry::DB()->build(array('select'=>'*','from'=>'market_reward_logs','where'=>"member_id=".ipsRegistry::member()->getProperty('member_id')." AND location='posts' AND l_time > ".$earliest,'order'=>'l_time ASC'));
				$q = ipsRegistry::DB()->execute();
				while($log = ipsRegistry::DB()->fetch($q))
				{
					$cached_posts[$log['l_time']] = $log['l_amount'];
				}
			}
			foreach($caches['market_taxes']['id'] as $tax)
			{
				$caches['market_taxes'][$tax['applying']][$tax['t_id']] = &$caches['market_taxes']['id'][$tax['t_id']];
				
				if( (!self::limitUpdate || self::$UPDATE < self::limitUpdate) )
				{
					if($tax['applying'] == 'hand')
					{
						if(!isset($last_collected[$tax['t_id']]))
						{
							for($t = ipsRegistry::member()->getProperty('joined'); $t < $time; $t += $tax['interval']);
							$last_collected[$tax['t_id']] = $t - 2 * $tax['interval'];
						}
						if(numbers::compare(ipsRegistry::member()->getProperty($settings['market_members_field']), $tax['range_min']) >= 0 && (numbers::compare(ipsRegistry::member()->getProperty($settings['market_members_field']), $tax['range_max']) <= 0 || !$tax['range_max']))
						{
							for($t = $last_collected[$tax['t_id']] + $tax['interval']; $t < $time; $t += $tax['interval'])
							{
								$percent = numbers::compare(ipsRegistry::member()->getProperty($settings['market_members_field']), $tax['range_pmin']) >= 0 && numbers::compare(ipsRegistry::member()->getProperty($settings['market_members_field']), $tax['range_psub']) > 0 ? numbers::subtract(ipsRegistry::member()->getProperty($settings['market_members_field']), $tax['range_psub']) : 0;
								$taxing = numbers::round(numbers::add($tax['tax_fix'], numbers::multiply($percent, $tax['tax_percent'], .01)));
								ipsRegistry::member()->setProperty($settings['market_members_field'], numbers::subtract(ipsRegistry::member()->getProperty($settings['market_members_field']), $taxing));
								$taxed = numbers::add($taxed,$taxing);
								ipsRegistry::DB()->do_insert('market_tax_logs',array(
																						'member_id' => ipsRegistry::member()->getProperty('member_id'),
																						'tax_id' => $tax['t_id'],
																						'amount' => $taxing,
																						'l_time' => $t,
																)					);
							}
						}
						else // Need to track the last update where it is no tax collected
						{
							for($t = $last_collected[$tax['t_id']]; $t < $time; $t += $tax['interval']);
							ipsRegistry::DB()->do_insert('market_tax_logs',array(
																					'member_id' => ipsRegistry::member()->getProperty('id'),
																					'tax_id' => $tax['t_id'],
																					'amount' => 0,
																					'l_time' => $t - $tax['interval'],
															)					);
						}
					}
					else
					{
						if(isset($last_collected[$tax['t_id']]))
						{
							for($t = $last_collected[$tax['t_id']] + $tax['interval']; $t < $time; $t += $tax['interval'])
							{
								$gained = 0;
								reset($cached_posts);
								while(list($t2, $gain) = each($cached_posts))
								{
									if($t2 < $t - $tax['interval'])
									{
										continue;
									}
									if($t2 > $t)
									{
										break;
									}
									$gained = numbers::add($gained, $gain);
								}
								if(numbers::compare($gained, $tax['range_min']) >= 0 && (numbers::compare($gained, $tax['range_max']) <= 0 || !$tax['range_max']))
								{
									$percent = numbers::compare($gained, $tax['range_pmin']) >= 0 && numbers::compare(ipsRegistry::member()->getProperty($settings['market_members_field']), $tax['range_psub']) > 0 ? numbers::subtract($gained, $tax['range_psub']) : 0;
									$taxing = numbers::round(numbers::add($tax['tax_fix'], numbers::multiply($percent,$tax['tax_percent'], .01)));
									ipsRegistry::member()->setProperty($settings['market_members_field'], numbers::subtract(ipsRegistry::member()->getProperty($settings['market_members_field']),$taxing));
									$taxed = numbers::add($taxed,$taxing);
									ipsRegistry::DB()->insert('market_tax_logs',array(
																						'member_id' => ipsRegistry::member()->getProperty('member_id'),
																						'tax_id' => $tax['t_id'],
																						'amount' => $taxing,
																						'l_time' => $t,
																)					);
									$last = $t;
								}
								if($t > end(array_keys($cached_posts)))
								{
									break;
								}
							}
							for($t; $t < $time; $t += $tax['interval']);
							if($last != $t - $tax['interval'])
							{
								ipsRegistry::DB()->insert('market_tax_logs',array(
																					'member_id' => ipsRegistry::member()->getProperty('member_id'),
																					'tax_id' => $tax['t_id'],
																					'amount' => 0,
																					'l_time' => $t - $tax['interval'],
															)					);
							}
						}
						else // Earliest time not to count for tax
						{
							for($t = ipsRegistry::member()->getProperty('joined'); $t < $time; $t += $tax['interval']);
							ipsRegistry::DB()->insert('market_tax_logs',array(
																				'member_id' => ipsRegistry::member()->getProperty('member_id'),
																				'tax_id' => $tax['t_id'],
																				'amount' => 0,
																				'l_time' => $t - $tax['interval'] * 2,
														)					);
						}
					}
					self::$UPDATE++;
				}
			}
			if($taxed != 0)
			{
				ipsRegistry::DB()->update('members',array(
															$settings['market_members_field'] => ipsRegistry::member()->getProperty($settings['market_members_field'])
					),"id=".ipsRegistry::member()->getProperty('member_id'));
			}
		}
		else
		{
			foreach($caches['market_taxes']['id'] as $tax)
			{
				$caches['market_taxes'][$tax['applying']][$tax['t_id']] = &$caches['market_taxes']['id'][$tax['t_id']];
			}
		}
		
		IPSDebug::setMemoryDebugFlag( "ibMarket: ibMarket process caches", $_pre_load );
	}
	
	/**
	 * Creates the order of the categories
	 *
	 * @access	private
	 * @return	void
	 */
	private static function buildCategoryOrder(&$categoryList, $parentCategory = -1, $depth = 0)
	{
		if(is_array(self::$categoryTree[$parentCategory]))
		{
			foreach(array_keys(self::$categoryTree[$parentCategory]) as $categoryID)
			{
				$categoryList[] = $categoryID;
				self::$categoryDepth[$categoryID] = $depth;
				self::buildCategoryOrder($categoryList, $categoryID, $depth + 1);
			}
		}
	}
	
	/**
	 * Gets the name of a class from the name of the file
	 * 
	 * @access	public
	 * @param	$file_location	The location of a file ending in .php
	 * @return	string			The class name
	 */
	public static function getClassName($file_location)
	{
		if(!$file_location)
		{
			return "";
		}
		
		$part = explode("/",$file_location);
		$filename = array_pop($part);
		
		if(substr($filename,-4) != '.php')
		{
			return "";
		}
		return substr($filename,0,strlen($filename)-4);
	}
	
	/**
	 * Gets the item object
	 * 
	 * @access	public
	 * @param	array	$item_info	The item information
	 * @param	array	[$store]	Tells the function to store it in the registry or bypass the registry
	 * @return	itemTemplate		The item object
	 */
	public static function getItem(&$item_info, $store = true)
	{
		if($store && is_object(self::$itemsLoaded[$item_info['item_id']]))
		{
			return self::$itemsLoaded[$item_info['item_id']];
		}
		$_pre_load = IPSDebug::getMemoryDebugFlag();
		
		if(!$item_info)
		{
			return null;
		}
		
		$class_name = self::getClassName($item_info['filename']);
		if(!$class_name)
		{
			return null;
		}
		require_once(IPSLib::getAppDir('ibmarket')."/items/".$item_info['filename']);
		$reflection = new ReflectionClass($class_name);
		if(!$reflection->isSubClassOf(self::$itemTemplate))
		{
			return null;
		}
		$registry = ipsRegistry::instance();
		$item = $reflection->newInstanceArgs(array(&$registry,&$item_info));
		
		if($store)
		{
			self::$itemsLoaded[$item_info['item_id']] = $item;
		}
		
		IPSDebug::setMemoryDebugFlag( "ibMarket: ibMarket item loaded: ".$item_info['item_name'], $_pre_load );
		
		return $item;
	}
	
	/**
	 * @deprecated
	 * @access	public
	 * @return	array
	 */
	public static function get_file_list($dir, $subfolders = 1, $include_folder = 0, $extra = "")
	{
		$files = array();
		if ( file_exists($dir) )
		{
			if ( is_dir($dir) )
			{
				$handle = opendir($dir);
				while (($filename = readdir($handle)) !== false)
				{
					if (($filename != ".") && ($filename != ".."))
					{
						if ( is_dir( $dir."/".$filename ) )
						{
							if($include_folder)
							{
								$files[] = $extra.$filename;
							}
							if($subfolders)
							{
								$files = array_merge($files,self::get_file_list($dir."/".$filename,$subfolders,$include_folder,$extra.$filename."/"));
							}
						}
						else
						{
							$files[] = $extra.$filename;
						}
					}
				}
				closedir($handle);
			}
		}
		return $files;
	}
	
	/**
	 * @deprecated
	 * @access	public
	 * @return	array
	 */
	public static function get_dir_list($dir, $subfolders = 1, $extra = "")
	{
		$files = array();
		if ( file_exists($dir) )
		{
			if ( is_dir($dir) )
			{
				$handle = opendir($dir);
				while (($filename = readdir($handle)) !== false)
				{
					if (($filename != ".") && ($filename != ".."))
					{
						if ( is_dir( $dir."/".$filename ) )
						{
							$files[] = $extra.$filename;
							if ( $subfolders )
							{
								$files = array_merge($files,self::get_dir_list($dir."/".$filename,$subfolders,$extra.$filename."/"));
							}
						}
					}
				}
				closedir($handle);
			}
		}
		return $files;
	}
	
	/**
	 * @deprecated
	 * @access	public
	 * @return	string
	 */
	public static function get_external_file($url)
	{
		$file = @file_get_contents($url);
		return $file;
	}
	
	/**
	 * Checks if the date and time inputted is a correct time
	 *
	 * @access	public
	 * @param	int		$month	The month
	 * @param	int		$day	The day of month
	 * @param	int		$year	The year
	 * @param	int		$hour	The hour
	 * @param	int		$minute	The minute
	 * @return	boolean	TRUE if the date and time is valid, false otherwise
	 */
	public static function checkLegalDateTime($month, $day, $year, $hour, $minute)
	{
		return checkdate( $month, $day, $year ) and $hour >= 0 and $hour < 24 and $minute >= 0 and $minute < 60;
	}
	
	/**
	 * Calculates the next restocking time for an item
	 *
	 * @access	public
	 * @param	array	$item	The item
	 * @param	int		[$time]	The last restock time
	 * @return	int		The next time to restock in UNIX time
	 */
	public static function nextRestockTime(array $item, $time = null)
	{
		if($time == null)
		{
			if($item['restock'] == 3)
			{
				$time = $item['restock_when'];
			}
			else
			{
				$time = IPS_UNIX_TIME_NOW;
			}
		}
		// Infinite stock
		if(numbers::compare($item['stock']) < 0) 
		{
			return 0;
		}
		// Stock it not at the right amount
		if(($item['restock'] == 1 || $item['restock'] == 2) && numbers::compare($item['stock'],$item['restock_when']) > 0)
		{
			return 0;
		}
		if($item['restock'] == 1)
		{
			$next = $item['restock_day'] * 86400 + $item['restock_hour'] * 3600 + $item['restock_minute'] * 60;
			
			return $time + $next;
		}
		elseif($item['restock'] == 3)
		{
			if($item['restock_when'] > $time)
			{
				return $item['restock_when'];
			}
			$interval = max($item['restock_day'] * 86400 + $item['restock_hour'] * 3600 + $item['restock_minute'] * 60, 1);
			$diff = $item['restock_when'] % $interval;
			$num_interval = floor($time / $interval) + 1;
			
			return $num_interval * $interval + $diff;
		}
		elseif($item['restock'] == 2 || $item['restock'] == 4)
		{
			$time_info = array_combine(array('seconds','minutes','hours','mday','wday','mon','year','yday','weekday','month',0),split(":",gmdate('s:i:G:j:w:n:Y:z:l:F:U',$time)));
			
			$add = 0;
			if($item['restock_day'] != 7)
			{
				$add += ($item['restock_day'] - $time_info['wday']) * 86400;
			}
			if($item['restock_hour'] != 24)
			{
				$add += ($item['restock_hour'] - $time_info['hours']) * 3600;
			}
			$add += ($item['restock_minute'] - $time_info['minutes']) * 60;
			if($add <= 0)
			{
				if($item['restock_day'] != 7)
				{
					$add += 604800;
				}
				elseif($item['restock_hour'] != 24)
				{
					$add += 86400;
				}
				else
				{
					$add += 3600;
				}
			}
			
			return $time_info[0] + $add - $time_info['seconds'];
		}
		
		return 0;
	}
	
	/**
	 * Calculates the next wage time for a wage
	 *
	 * @access	public
	 * @param	array	$wage	The wage
	 * @param	int		[$time]	The last wage given time
	 * @return	int		The next time to give wage in UNIX time
	 */
	public static function nextWageTime(array $wage, $time = 0)
	{
		if(!$time)
		{
			if($wage['w_how'] == 1)
			{
				$time = $wage['w_when'];
			}
			else
			{
				$time = IPS_UNIX_TIME_NOW;
			}
		}
		if($wage['w_how'] == 1)
		{
			if($wage['w_when'] > IPS_UNIX_TIME_NOW)
			{
				return $wage['w_when'];
			}
			$interval = max($wage['w_day'] * 86400 + $wage['w_hour'] * 3600 + $wage['w_minute'] * 60,1);
			$diff = $wage['w_when'] % $interval;
			$num_interval = floor($time / $interval) + 1;
			
			return $num_interval * $interval + $diff;
		}
		elseif($wage['w_how'] == 2)
		{
			$time_info = array_combine(array('seconds','minutes','hours','mday','wday','mon','year','yday','weekday','month',0),split(":",gmdate('s:i:G:j:w:n:Y:z:l:F:U',$time)));
			
			$add = 0;
			if($wage['w_day'] != 7)
			{
				$add += ($wage['w_day'] - $time_info['wday']) * 86400;
			}
			if($wage['w_hour'] != 24)
			{
				$add += ($wage['w_hour'] - $time_info['hours']) * 3600;
			}
			$add += ($wage['w_minute'] - $time_info['minutes']) * 60;
			if($add <= 0)
			{
				if($wage['w_day'] != 7)
				{
					$add += 604800;
				}
				elseif($wage['w_hour'] != 24)
				{
					$add += 86400;
				}
				else
				{
					$add += 3600;
				}
			}
			
			return $time_info[0] + $add - $time_info['seconds'];
		}
		
		return 0;
	}
	
	/**
	 * Logs a fee within ibMarket
	 *
	 * @access	public
	 * @param	int|string	$howMuch	The amount
	 * @param	int			[$time]		The time
	 * @return	void
	 */
	public static function recordFee($howMuch, $time = IPS_UNIX_TIME_NOW)
	{
		if(!$howMuch)
		{
			return;
		}
		
		$input =& ipsRegistry::fetchRequest();
		$caches =& ipsRegistry::cache()->fetchCaches();
		$location = "";
		if($input['module'] == 'shop')
		{
			$location = 'buy';
		}
		if($input['module'] == 'plugin')
		{
			$location = "plugin:".$input['plugin'].":".$caches['market_plugin'][$input['plugin']]['name'];
		}
		if($input['module'] == 'inventory' && $input['section'] == 'item')
		{
			$inventoryItems = self::getInventoryItem(ipsRegistry::member()->member_id);
			$location = "item:".$input['item'].":".$caches['market_items'][$inventoryItems[$input['item']]['item']]['item_name'];
		}
		
		ipsRegistry::DB()->insert('market_fee_logs',array(
															'member_id' => ipsRegistry::member()->getProperty('member_id'),
															'l_time' => $time,
															'location' => $location,
															'l_amount' => $howMuch,
									)					);
	}
	
	/**
	 * Logs a reward within ibMarket
	 *
	 * @access	public
	 * @param	int|string	$howMuch	The amount
	 * @param	int			[$time]		The time
	 * @return	void
	 */
	public static function recordReward($howMuch,$time = IPS_UNIX_TIME_NOW)
	{
		if(!$howMuch)
		{
			return;
		}
		
		$input =& ipsRegistry::fetchRequest();
		$caches =& ipsRegistry::cache()->fetchCaches();
		$location = "";
		if($input['module'] == 'plugin')
		{
			$location = "plugin:".$input['plugin'].":".$caches['market_plugin'][$input['plugin']]['name'];
		}
		if($input['module'] == 'inventory' && $input['section'] == 'item')
		{
			$inventoryItems = self::getInventoryItem(ipsRegistry::member()->member_id);
			$location = "item:".$input['item'].":".$caches['market_items'][$inventoryItems[$input['item']]['item']]['item_name'];
		}
		
		ipsRegistry::DB()->insert('market_reward_logs',array(
																'member_id' => ipsRegistry::member()->getProperty('member_id'),
																'l_time' => $time,
																'location' => $location,
																'l_amount' => $howMuch,
									)						);
	}
	
	/**
	 * Get the items array organized by file
	 *
	 * @access	public
	 * @param	string	[$file]		The file location
	 * @param	int		[$itemID]	The item id
	 * @return	array
	 */
	public static function getItemsByFiles($file = null, $itemID = null)
	{
		if(is_null($file))
		{
			return self::$itemByFiles;
		}
		else
		{
			if(is_null($itemID))
			{
				return self::$itemByFiles[$file];
			}
			else
			{
				return self::$itemByFiles[$file][$itemID];
			}
		}
	}
	
	/**
	 * Get the items array organized by category
	 *
	 * @access	public
	 * @param	int	[$categoryID]	The category ID
	 * @param	int	[$itemID]		The item id
	 * @return	array
	 */
	public static function getItemsByCategory($categoryID = null, $itemID = null)
	{
		if(is_null($categoryID))
		{
			return self::$itemByCategories;
		}
		else
		{
			if(is_null($itemID))
			{
				return self::$itemByCategories[$categoryID];
			}
			else
			{
				return self::$itemByCategories[$categoryID][$itemID];
			}
		}
	}
	
	/**
	 * Get the categories array organized by category parent
	 *
	 * @access	public
	 * @param	int	[$parentID]		The category ID (parent)
	 * @param	int	[$categoryID]	The category ID (child)
	 * @return	array
	 */
	public static function getCategoryTree($parentID = null, $categoryID = null)
	{
		if(is_null($parentID))
		{
			return self::$categoryTree;
		}
		else
		{
			if(is_null($categoryID))
			{
				return self::$categoryTree[$parentID];
			}
			else
			{
				return self::$categoryTree[$parentID][$categoryID];
			}
		}
	}
	
	/**
	 * Get the categories order array organized by category tree
	 *
	 * @access	public
	 * @param	int	[$order]	The order of the placement
	 * @return	array|int
	 */
	public static function getCategoryOrder($order = null)
	{
		if(is_null($order))
		{
			return self::$categoryOrder;
		}
		else
		{
			return self::$categoryOrder[$order];
		}
	}
	
	/**
	 * Get the category's depth
	 *
	 * @access	public
	 * @param	int	[$categoryID]	The category ID
	 * @return	array|int
	 */
	public static function getCategoryDepth($categoryID = null)
	{
		if(is_null($categoryID))
		{
			return self::$categoryDepth;
		}
		else
		{
			return self::$categoryDepth[$categoryID];
		}
	}
	
	/**
	 * Get the icons in an array
	 *
	 * @access	public
	 * @return	array
	 */
	public static function getIconsList()
	{
		if(!count(self::$iconsList))
		{
			foreach(new DirectoryIterator(self::$image_server_path."/icons") as $file)
			{
				if($file->isFile() && preg_match("/(.jpg|.gif|.png)/",$file->getFilename()))
				{
					self::$iconsList[] = $file->getFilename();
				}
			}
		}
		return self::$iconsList;
	}
	
	/**
	 * Getting all the menu links to the plugins
	 *
	 * @access	public
	 * @param	string	[$pluginLink]
	 * @return	array
	 */
	public static function getMenuLinks($pluginDirectory = null)
	{
		static $menu = null;
		if(is_null($menu))
		{
			$menu = array();
			foreach(ipsRegistry::cache()->getCache('market_plugin') as $directory => $plugin)
			{
				$menu[$directory] = array();
				
				if(file_exists(IPSLib::getAppDir('ibmarket')."/plugins/".$directory."/publicMenu.php"))
				{
					$MENU = array();
					require(IPSLib::getAppDir('ibmarket')."/plugins/".$directory."/publicMenu.php");
					
					if(is_array($MENU) && count($MENU))
					{
						foreach($MENU as $_menu)
						{
							if($_menu['permission'] === TRUE || marketRegistry::hasPluginPermission($_menu['permission'],$directory))
							{
								$menu[$pluginDirectory][] = $_menu;
							}
						}
					}
				}
			}
		}
		if(is_null($pluginDirectory))
		{
			return $menu;
		}
		else
		{
			return $menu[$pluginDirectory];
		}
	}
	
	/**
	 * Getting all the menu links to the plugins
	 *
	 * @access	public
	 * @param	int	$member_id
	 * @return	array
	 */
	public static function getInventoryItem($member_id)
	{
		if(isset(self::$inventoryItem[$member_id]))
		{
			return self::$inventoryItem[$member_id];
		}
		
		$caches =& ipsRegistry::cache()->fetchCaches();
		self::$inventoryItem[$member_id] = array();
		ipsRegistry::DB()->build(array('select'=>'*','from'=>'market_inventory','where'=>"member_id=".$member_id,'order'=>"time_bought ASC, item ASC"));
		$q = ipsRegistry::DB()->execute();
		$toDelete = array();
		while($inv = ipsRegistry::DB()->fetch($q))
		{
			if(!is_array($caches['market_items'][$inv['item']]))
			{
				$toDelete[] = $inv['i_id'];
				continue;
			}
			if($inv['expired'] && $inv['expired'] < IPS_UNIX_TIME_NOW)
			{
				continue;
			}
			self::$inventoryItem[$member_id][$inv['i_id']] = $inv;
		}
		if(count($toDelete))
		{
			ipsRegistry::DB()->delete('market_inventory',"i_id IN (".implode(", ",$toDelete).")");
		}
		
		return self::$inventoryItem[$member_id];
	}
	
	/**
	 * For ACP
	 * Generates the HTML input for item table
	 *
	 * @access	public
	 * @param	string	$id
	 * @param	array	$defaultValue	The default value for this input
	 * @return	array
	 */
	public static function formItemTable($id, array $defaultValue)
	{
		static $html = null;
		if(!$html)
		{
			$html = ipsRegistry::getClass('output')->loadTemplate('cp_skin_splash');
		}
		
		return $html->itemTable($id, $defaultValue);
	}
	
	/**
	 * For ACP
	 * Process the input of item table
	 *
	 * @access	public
	 * @param	string|array	$field
	 * @return	array
	 */
	public static function processItemTable($field)
	{
		$items = array();
		
		if(!is_array($field))
		{
			$field = array($field);
		}
		static $_input = false;
		static $caches = false;
		if($_input === false)
		{
			$_input =& ipsRegistry::fetchRequest();
		}
		if($caches === false)
		{
			$caches =& ipsRegistry::cache()->fetchCaches();
		}
		
		$input = $_input;
		foreach($field as $f)
		{
			$input = $input[$f];
		}
		
		if($input == "")
		{
			return $items;
		}
		
		foreach(explode(",",$input) as $part)
		{
			list($itemID, $quanity) = explode("=",$part);
			$itemID = intval($itemID);
			$quanity = numbers::parseInt($quanity);
			if(!is_array($caches['market_items'][$itemID]) || $quanity <= 0)
			{
				continue;
			}
			$items[$itemID] += $quanity;
		}
		return $items;
	}
	
	/**
	 * Load a plugin template file
	 *
	 * @access	public
	 * @param	string		Template name
	 * @param	string		Application [defaults to current application]
	 * @return	object
	 */
	public static function loadTemplate( $template, $plugin='' )
	{
		$plugin = $plugin ? $plugin : ipsRegistry::$request['plugin'];
		
		if(!$plugin)
		{
			throw new Exception("No plugin could have been loaded");
		}
		
		/* Skin file exists? */
		if ( file_exists( IPSLib::getAppDir('ibmarket')."/plugins/".$plugin."/skin_cp/".$template.".php" ) )
		{
			$_pre_load = IPSDebug::getMemoryDebugFlag();
			
			require_once( IPSLib::getAppDir('ibmarket')."/plugins/".$plugin."/skin_cp/".$template.".php" );
			
			IPSDebug::setMemoryDebugFlag( "CORE: Template Loaded ($template)", $_pre_load );
			
			return new $template( ipsRegistry::instance() );
		}
		else
		{
			ipsRegistry::$output->showError( "Could not locate template: $template", 4100, true );
		}
	}
	
	/**
	 * Check permissions for plugin
	 *
	 * @access	public
	 * @param	string		'use'|'view'
	 * @param	string		Plugin directory
	 * @param	array		Member Data
	 * @return	boolean
	 */
	public static function hasPluginPermission( $type, $plugin='', array $member=null )
	{
		if(!$member)
		{
			$member = ipsRegistry::member()->fetchMemberData();
		}
		
		if(!$plugin)
		{
			if(!isset(ipsRegistry::$request['plugin']))
			{
				return false;
			}
			
			$plugin = ipsRegistry::$request['plugin'];
		}
		
		static $permissions = null;
		if(is_null($permissions))
		{
			$permissions = array();
		}
		if(isset($permissions[$member['member_group_id']][$plugin][$type]))
		{
			return $permissions[$member['member_group_id']][$plugin][$type];
		}
		
		$caches =& ipsRegistry::cache()->fetchCaches();
		return $permissions[$member['member_group_id']][$plugin][$type] = in_array($member['member_group_id'], $caches['market_plugin'][$plugin][$type.'_permission']);
	}
}

marketRegistry::__init();
?>